package com.lap.auth.adapter.driving.ports;

import com.lap.auth.shared.configure.JwtProperties;
import com.lap.auth.shared.errors.LoginError;
import com.lap.auth.shared.ports.JwtService;
import com.lap.framework.common.exception.BizException;
import com.lap.framework.common.tool.Uid;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import javax.crypto.SecretKey;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class JwtServiceImpl implements JwtService {

  private static final String USER_ID = "id";

  private final JwtProperties jwtProperties;

  // =====================
  // 生成 Token
  // =====================
  @Override
  public String accessToken(Integer userId) {
    return buildToken(userId, jwtProperties.getAccessTokenTtl());
  }

  @Override
  public String refreshToken(Integer userId) {
    return buildToken(userId, jwtProperties.getRefreshTokenTtl());
  }

  @Override
  public Date expiration() {
    Instant expireAt = Instant.now().plus(Duration.ofMinutes(jwtProperties.getAccessTokenTtl()));
    return Date.from(expireAt);
  }

  private String buildToken(Integer userId, int ttlMinutes) {
    Instant now = Instant.now();
    Instant expireAt = now.plus(Duration.ofMinutes(ttlMinutes));

    return Jwts.builder()
        .id(Uid.getCompactId())
        .issuer(String.valueOf(userId))
        .claim(USER_ID, userId)
        .issuedAt(Date.from(now))
        .expiration(Date.from(expireAt))
        .signWith(getSignKey())
        .compact();
  }

  // =====================
  // 解析 Token
  // =====================
  @Override
  public Integer validateJwt(String token) {
    try {
      Claims claims = jwtParser().parseSignedClaims(token).getPayload();
      return claims.get(USER_ID, Integer.class);
    } catch (ExpiredJwtException e) {
      throw BizException.newBiz(LoginError.LOGIN_EXPIRED);
    } catch (Exception e) {
      throw BizException.newBiz(LoginError.LOGIN_TOKEN_ERROR);
    }
  }

  private JwtParser jwtParser() {
    return Jwts.parser().verifyWith(getSignKey()).build();
  }

  // =====================
  // 秘钥
  // =====================
  private SecretKey getSignKey() {
    byte[] keyBytes = Decoders.BASE64.decode(jwtProperties.getSecretKey());
    return Keys.hmacShaKeyFor(keyBytes);
  }
}
